package openadmin.dao.operation;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;

import com.csvreader.CsvWriter;

import openadmin.dao.Base;
import openadmin.dao.exception.DataException;
import openadmin.dao.exception.ErrorDao;
import openadmin.model.log.Detail;
import openadmin.model.log.Log;
import openadmin.util.configuration.TypeLanguages;
import openadmin.util.reflection.ReflectionField;

/**
 * <desc>LogDao are used to persist information in database about the operations of Log </desc>
 * <responsibility>registered all operation in database</responsibility>
 * <coperation>Implements LogOperationFacade</coperation>
 * @version  0.1
 * Create  18-03-2009
 * Author Alfred Oliver
*/
public class LogDao implements LogOperationFacade {

	/** Field that contain the working language*/
	private ResourceBundle languageLog = ResourceBundle.getBundle("messagesLog_ca");
	
	/** Field with database connection*/
	private DaoOperationFacade connectDao = null;
	
	/** Work program*/
	private String program = "control";
	
	private List<String> listLog = new ArrayList<String>();
	
	private Base objectOriginal = null;
	
	private Base objectUpdate = null;
	
	/** State debug*/
	private boolean debugLog = true;
	
	/** State historic*/
	private boolean historicLog = false;
	
	/** State trace*/
	private boolean trace = false;
	
	/** File to registered log*/
	private CsvWriter logtxt;
	
	
	/**
	  * Constructor of class LogDao.
	  * @throws DataException. 
	  * @param pConnect. Connection database.  	 
	  * @param 	pProgram. Work program.	
	  */
	public LogDao(DaoOperationFacade pConnect, String pProgram)
			throws DataException {
		
		this.program = pProgram;
		connectDao = pConnect;
		listLog.clear();
		listLog.add(null);
		listLog.add(null);
		listLog.add(null);
		listLog.add(language("CONNECTION_LOG"));		
		recordLog(listLog);	
				
	}
	
	
	/**
	  * Procedure open file trace. 
	  */
	  public void openTrace() {
		  
		  logtxt = new CsvWriter ("c:/log" +  DateFormat.getDateInstance().format(Calendar.getInstance().getTime()) + ".csv");
		  this.trace = true;
	  }
	  
	 /**
	   * Procedure closed file trace.
	   */
	  public void closedTrace() {
		  
		  if (trace){
				logtxt.close();
				this.trace = false;
			}
	  }	
	
	 public void detailLog(Base objectOriginal, Base objectUpdate){
		 
		 this.objectOriginal = objectOriginal;
		 this.objectUpdate = objectUpdate;
		 
	 }
	  
	  
	 /**
	 * <desc> Registered action done</desc>
	 * @param pAccio, Action done	
	 * @throws DataException 
	 */
	public void recordLog(List<String> listLog) throws DataException{
						
		if (!debugLog || connectDao == null || connectDao.getUser() == null) {
			
			return;
		}
		
		Log log = new Log();
					 
		try {
			
			log.setProgram(program);
			log.setPerson(connectDao.getUser().getDescription() + " - " + InetAddress.getLocalHost());			
			log.setObject(listLog.get(0));
			log.setIdobject(listLog.get(1));
			log.setAction(listLog.get(2));
			log.setDescription(listLog.get(3));
			log.setData(Calendar.getInstance().getTime());	
			
			if (historicLog & objectOriginal != null & objectUpdate != null ){
								
				log.setDetail(analyzerAttribute(log));
				objectNull();				
								
			}
		
			//Per ammagatzemar en la base de dades control							
			connectDao.getEntityManager().getTransaction().begin();
			connectDao.getEntityManager().persist(log);		
			connectDao.getEntityManager().getTransaction().commit();	
			
			
		} catch (UnknownHostException ex) {
				
			throw new DataException(ErrorDao.LOG, ex.getMessage(),
					ex.getClass().getName(),
					connectDao.getLanguage(),
					connectDao.getEnvironment());
			
		} catch (Exception ex) {
			
			throw new DataException(ErrorDao.LOG, ex.getMessage(),
					ex.getClass().getName(),
					connectDao.getLanguage(),
					connectDao.getEnvironment());
		}
		
		
		/**	
		System.out.println("Log: " + log.getData()+ ";" + 
				 					 log.getPerson() + ";" + 
									 log.getObject() + ";" + 
									 log.getIdobject() + ";" +
									 log.getAction() + ";" + 
									 log.getDescription());
		*/		
		if (trace){
			
			try {
				
				logtxt.write(log.getData()+ ";" + 
							 log.getPerson() + ";" + 
							 log.getObject() + ";" + 
							 log.getIdobject() + ";" +
							 log.getAction() + ";" + 
							 log.getDescription());
				logtxt.endRecord();
									
			} catch (Exception ex) {
				
				throw new DataException(ErrorDao.LOG, ex.getMessage(),
						ex.getClass().getName(),
						connectDao.getLanguage(),
						connectDao.getEnvironment());
			}
			
		}										
	
	}

	public void setLanguageLog(TypeLanguages pLanguage) {
		
		languageLog = ResourceBundle.getBundle("messagesLog_" + pLanguage);
	}
	
	public String language(String pKey){
		String s=pKey+" NOT FOUND";
		try {
			s=languageLog.getString(pKey);
		}catch (Exception e){
			e.printStackTrace();
		}
		return languageLog.getString(pKey);
	
	}
	
	public void finalizeLog() throws DataException{
		
		listLog.clear();
		listLog.add(null);
		listLog.add(null);
		listLog.add(null);
		listLog.add(language("END_CONNECTION"));		
		recordLog(listLog);									
		connectDao.finalize();
					
	}
	
	public void activateLog(Boolean pDebug){
		
		this.debugLog = pDebug;
		
	}
	
	public void activatehistoric(Boolean pHistoric){
		
		this.historicLog = pHistoric;
		
	}
	
	public void changeProgram(String pProgram){
		
		program = pProgram;
		
	}
	
	private Set<Detail> analyzerAttribute(Log log){
		
		boolean result = false;
		
		Set<Detail> listdetail = new HashSet<Detail>(0);				
		
		ReflectionField rf = new ReflectionField();
		
		List<String[]> fieldObjectOriginal = rf.execute(objectOriginal);
						
		List<String[]> fieldObjectUpdate = rf.execute(objectUpdate);
				
		listdetail.clear();
		
		for (String pPropertyFieldUpdate[]: fieldObjectUpdate){
			
			result = false;
			
			for (String pPropertyFieldOriginal[]: fieldObjectOriginal){								
				
				//System.out.println("Atribut ori " + pPropertyFieldOriginal[0] + " Valor ori " + pPropertyFieldOriginal[2]);
				//System.out.println("Atribut upd " + pPropertyFieldUpdate[0] + " Valor upd " + pPropertyFieldUpdate[2]);
				//System.out.println("---------------------------------------------------------------- ");
				
				if (pPropertyFieldUpdate[0].toString().compareTo(pPropertyFieldOriginal[0].toString())== 0){										
					
					result = true;
					
					if (!pPropertyFieldUpdate[2].toString().equals(pPropertyFieldOriginal[2].toString())){												
						
						Detail detail = new Detail();
						detail.setAttribute(pPropertyFieldOriginal[0].toString());						
						detail.setValue(pPropertyFieldOriginal[2].toString());
						detail.setDescription();						
						detail.setLog(log);
						listdetail.add(detail);
					}
					
					break;
				}
				
			}
			
			if (!result){
			
				//System.out.println("Atribut upd " + pPropertyFieldUpdate[0] + " Valor upd " + pPropertyFieldUpdate[2]);	
				Detail detail = new Detail();
				detail.setAttribute(pPropertyFieldUpdate[0].toString());						
				detail.setValue("null");
				detail.setDescription();						
				detail.setLog(log);
				listdetail.add(detail);
				
			}			
		}
		
		return listdetail;
	}
	
	private void objectNull(){
		
		objectOriginal = null;
		objectUpdate = null;
	}
}
